#include "global.h"
#include "cvt.h"
DOUBLE MAXIMUM = 10;

void CVT::convert_face_polygon(unsigned i, Polygon & polygon)
{
	Vertex_handle v_handle = vertex_index[i];
	Edge_circulator	 e_begin = incident_edges (v_handle);
	Edge_circulator  ec = e_begin;
	do 
	{
		if (is_infinite(ec)) continue;
		//std::cout<<segment(ec)<<"   ";
		CGAL::Object o = dual(ec);
		if ( CGAL::object_cast<K::Segment_2>(&o)) 
		{
			Segment s;
			s =  * CGAL::object_cast<K::Segment_2>(&o);
			if (s.is_degenerate ()) continue;
			//std::cout<<"This is a segment"<< s<<std::endl;
			polygon.push_back(s.target());
		}
    		else if (CGAL::object_cast<K::Ray_2>(&o)) 
    		{
    			Ray ray;
    			Segment s;
    			ray =  * CGAL::object_cast<K::Ray_2>(&o);
    			if (ray.is_degenerate()) continue;
    			Point p = vertex_index[i]->point();
    			convert_ray_diseg (ray, s, p, MAXIMUM);
    			if (ray.point(0) == s.source())
    			{
    				polygon.push_back(s.target());
			}
			else
			{
				polygon.push_back(s.source());
				polygon.push_back(s.target());
			}
    			//std::cout<<"This is a ray "<<s<<std::endl;
    		}
    		else if (CGAL::object_cast<K::Line_2> (&o))
    		{
	    		std::cout<<"This is a line"<<std::endl;
    		}		
	} while (++ec != e_begin);

}
bool CVT::intersect (const Polygon & p1, const Polygon & p2, Polygon & p_result)
{
	
	
	std::ostringstream ostr(std::ostringstream::out);
	std::ostream_iterator<Polygon_h > sit = ostr;
	
  	intersection(p1, p2, sit); 
  	
	
	std::istringstream istr(ostr.str());
  	int numberofedge ;
  	istr>>numberofedge;
  	for (int i = 0; i < numberofedge; ++i)
  	{
  		Point p;
  		istr>> p;
  		p_result.push_back(p);
  	}
	return true;
}
void CVT::convert_face_region  (unsigned i, Polygon & polygon)
{
	Polygon p;
	convert_face_polygon (i, p);
	intersect(p, this->m_bound, polygon);
	
}
void CVT::convert_seg_diseg (Segment & seg, Segment & result, Point & site)
{
	Point p1 = seg.source();
	Point p2 = seg.target();
	
	Point p3 ( p1.x() - site.x(), p1.y()- site.y()) ;
	Point p4 ( p2.x() - site.x(), p2.y()- site.y()) ;
	
	if (p3.x() * p4.y() - p3.y() * p4.x() > 0)
	{
		result = Segment (seg.source(), seg.target());
	}
	else
	{
		result = Segment (seg.target(), seg.source());
	}
	
}
void CVT::convert_ray_diseg (Ray & ray, Segment & seg, Point & site, unsigned length)
{
	Point p1 = ray.point(0);
	Point p2 = ray.point(length);
	
	Point p3 ( p1.x() - site.x(), p1.y()- site.y()) ;
	Point p4 ( p2.x() - site.x(), p2.y()- site.y());
	
	if (p3.x() * p4.y() - p3.y() * p4.x() > 0)
	{
		seg = Segment (ray.point(0), ray.point(length));
	}
	else
	{
		seg = Segment (ray.point(length), ray.point(0));
	}
}
void CVT::convert_line_segment (Line & ray, Segment & s, unsigned length)
{
	
}
void centroid (Polygon & polygon, Point & centroid)
{
	DOUBLE area = 0;
	unsigned size = polygon.size();
	for (unsigned i = 0 ; i < size ; ++i)
	{
		DOUBLE x1 = polygon[i % size].x();
		DOUBLE y1 = polygon[i % size].y();
		DOUBLE x2 = polygon[(i+1) % size].x();
		DOUBLE y2 = polygon[(i+1) % size].y();
		
		area += x1*y2 - x2* y1;
	}
	area /= 2.0;
	//std::cout<<"area"<< area<<std::endl;
	DOUBLE cx = 0;
	DOUBLE cy = 0;
	for (unsigned i = 0 ; i < size; ++i)
	{
		DOUBLE x1 = polygon[i % size].x();
		DOUBLE y1 = polygon[i % size].y();
		DOUBLE x2 = polygon[(i+1) % size].x();
		DOUBLE y2 = polygon[(i+1) % size].y();
		
		cx += (x1+x2) * (x1*y2 - x2*y1);
		cy += (y1+y2) * (x1*y2 - x2*y1);		
	}
	cx /= (6*area);
	cy /= (6*area);
	centroid = Point (cx, cy);
}
DOUBLE energy_function (std::vector<Point> & oldseeds, std::vector<Point> & newseeds)
{
      
	//static DOUBLE old_energy = 0;
       	DOUBLE e = 0;
       	assert (oldseeds.size() == newseeds.size());
       	for (unsigned int i = 0; i < oldseeds.size(); ++i)
       	{
               	DOUBLE x1 = oldseeds[i].x();
               	DOUBLE y1 = oldseeds[i].y();
               	DOUBLE x2 = newseeds[i].x();
               	DOUBLE y2 = newseeds[i].y();
               	e = e + (x1-x2) * (x1-x2) + (y1 - y2) * (y1 - y2); 
       	}
        //e = abs(old_energy-e);
        //old_energy = e;
       	return e;
}
void faces_centroid (std::vector <Polygon> & faces, std::vector <Point> & centroids)
{
        Point c; 
        for (unsigned int i = 0; i < faces.size(); ++i) 
        {
        	assert (faces[i].size());
                centroid (faces[i], c);
                centroids.push_back(c);
        }
}

//CVT::FACE_TYPE CVT::face_type (unsigned i)
//{
//	if (!f->is_unbounded()) return BOUNDED;
//	
//	Ccb_halfedge_circulator ec_start = f->outer_ccb();
//	Ccb_halfedge_circulator ec = ec_start;
//	Ccb_halfedge_circulator testec = ec_start;
//	if (++testec == ec_start) return ONE_LINE;
//	if (++testec == ec_start && !ec_start->has_source() && !ec_start->has_target()) return TWO_LINE;
//	return TWO_RAY;
//}
/*
int main()
{
	CVT obj;
	obj.insert (Point (1,0));
	obj.insert (Point (-1,0));
	obj.insert (Point (0,1));
	obj.insert (Point (0,-1));
	//obj.move (3, Point (2.5,1));
	//obj.move (3, Point (5.5,1));
	
	for ( int i = 0; i < 4; ++i)
	{
		Polygon p;
		obj.convert_face_polygon(i, p);
		std::cout<<"Polygon Begin"<<std::endl;
		std::cout<<p << std::endl;
		std::cout<<"Polygon End"<<std::endl;
	}
	
	obj.move (2, Point (0, -2));
	obj.move (3, Point (0, 2));
	
	for ( int i = 0; i < 4; ++i)
	{
		Polygon p;
		obj.convert_face_polygon(i, p);
		std::cout<<"Polygon Begin"<<std::endl;
		std::cout<<p << std::endl;
		std::cout<<"Polygon End"<<std::endl;
	}	
	//obj.print_vertex_ordered();
	
	//obj.print_vertex();
	return 0;
}
*/
/*
int main()
{
	int numbound;
	Polygon bound;
	std::vector<Point> v_p;
	std::cin>>numbound;
	for (int i = 0; i < numbound; ++i)
	{
		Point p;
		std::cin>>p;
		bound.push_back(p);
	}
	
	int numseeds;
	std::cin>>numseeds;
	for (int i = 0; i < numseeds; ++i)
	{
		Point p;
		std::cin>>p;
		v_p.push_back(p);
	}
        

	CVT obj(bound,v_p);
	std::cout<<obj.size()<<std::endl;
	for (unsigned i = 0; i < obj.size(); ++i)
	{
		Polygon p;
		obj.convert_face_region(i, p);
		std::cout<<p<<std::endl;
	}
	//std::vector<Point>  result;
	//std::vector<Polygon>  faces;
    	//lloyd(v_p,  bound, result,  faces, 1e-8);
	//simple_increment (v_p, bound, result, faces, 1e-7);
    	

	return 0;
}
*/
